package edu.ncsu.csc.ip.routing.ls;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

public class AllPaths {

	public static final boolean DIRECTED_GRAPH = false;
	public static final double INFINITY = Double.POSITIVE_INFINITY;
	public long pathCount = 0;
	HashMap<String, Node> nodesMap = new HashMap<String, Node>();

	public void loadGraph(String fileName) throws IOException {
		File file;
		BufferedReader fileReader;

		file = new File(fileName);
		fileReader = new BufferedReader(new FileReader(file));
		String line;

		//int nodeCount = Integer.parseInt(fileReader.readLine());
		while ((line = fileReader.readLine()) != null) {

			String[] params = line.split("\\s+");
			double weight = Double.parseDouble(params[2]);
			if (!nodesMap.containsKey(params[0]))
				nodesMap.put(params[0], new Node(params[0]));
			if (!nodesMap.containsKey(params[1]))
				nodesMap.put(params[1], new Node(params[1]));

			nodesMap.get(params[0]).addNeighbour(new Edge(nodesMap.get(params[1]), weight));
			// System.out.println("'"+params[0] +"' to '"+ params[1] +"' > "+
			// weight);

			if (!DIRECTED_GRAPH) {
				nodesMap.get(params[1]).addNeighbour(new Edge(nodesMap.get(params[0]), weight));

				// System.out.println("'"+params[1] +"' to '"+ params[0]
				// +"' > "+ weight);
			}
		}

		fileReader.close();

		// if (nodeCount != nodesMap.size())
		// throw new RuntimeException(
		// "Number of nodes doesn't match the first line of the input");

	}

	public void findAllPaths(ArrayList<Node> visitedNodesSet, Node source,
			Node destination, int maxHop) {
		if (source == null || destination == null)
			throw new RuntimeException("Source or Destination is null!");
		if (source.equals(destination)) {
			pathCount++;
			print(visitedNodesSet, destination);
		} else {
			for (Edge edge : source.getNeighbours()) {
				Node adjacentNode = edge.getDestination();
				if (!visitedNodesSet.contains(adjacentNode)
						&& (visitedNodesSet.size() < maxHop)) {
					ArrayList<Node> newVisitedNodeSet = new ArrayList<Node>(
							visitedNodesSet);
					newVisitedNodeSet.add(source);
					findAllPaths(newVisitedNodeSet, adjacentNode, destination,
							maxHop);
				}
			}
		}
	}
	
	public ArrayList<ArrayList<Node>> getAllPathsList(ArrayList<Node> visitedNodesSet, Node source,
			Node destination, int maxHop) {
		ArrayList<ArrayList<Node>> pathList = new ArrayList<ArrayList<Node>>();
		if (source == null || destination == null)
			throw new RuntimeException("Source or Destination is null!");
		if (source.equals(destination)) {
			pathCount++;
			visitedNodesSet.add(destination);
			pathList.add(visitedNodesSet);
			return pathList;
			
		} else {
			for (Edge edge : source.getNeighbours()) {
				Node adjacentNode = edge.getDestination();
				if (!visitedNodesSet.contains(adjacentNode)
						&& (visitedNodesSet.size() < maxHop)) {
					ArrayList<Node> newVisitedNodeSet = new ArrayList<Node>(
							visitedNodesSet);
					newVisitedNodeSet.add(source);
					pathList.addAll(getAllPathsList(newVisitedNodeSet, adjacentNode, destination,
							maxHop));
				}
			}
			
			return pathList;
		}
		
	}

	public void print(ArrayList<Node> visitedNodes, Node destinNode) {
		System.out.print("[");
		for (Node node : visitedNodes) {
			System.out.print(node + ">");
		}
		System.out.print(destinNode + "] ");
		System.out.println(" cost: "+getCost(visitedNodes,destinNode));
	}
	
	
	public long getCost(ArrayList<Node> visitedNodes, Node destinNode) {
		int cost=0;
		Node previousNode = null;
		for (Node node : visitedNodes) {
			if(previousNode!=null){
			  cost+= (previousNode.getNeighboursMap().get(node).getWeight());
			}
			previousNode=node;
			
		}
		cost+= (previousNode.getNeighboursMap().get(destinNode).getWeight());
		return cost;
	}
	
	
	public long getCost(ArrayList<Node> visitedNodes) {
		int cost=0;
		Node previousNode = null;
		for (Node node : visitedNodes) {
			if(previousNode!=null){
			  cost+= (previousNode.getNeighboursMap().get(node).getWeight());
			}
			previousNode=node;
			
		}
		return cost;
	}

	public static void main(String[] args) throws IOException {
		AllPaths allPaths = new AllPaths();
		allPaths.loadGraph("./network/warehouses.txt");
		System.out.println("Graph Loaded");

		// for (Node node : allPaths.nodesMap.values()) {
		// System.out.println(":: " + node);
		// for(Edge e:node.getNeighbours()){
		// System.out.println("		 " + e.getDestination());
		// }
		// }
		allPaths.findAllPaths(new ArrayList<Node>(),
				allPaths.nodesMap.get("Kerman"),
				allPaths.nodesMap.get("Tehran"), 6);
		System.out.println("Path Count: " + allPaths.pathCount);
	}

}
